/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.connection;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * The RCSSConnection handles a bidirectional connection to the soccer server.
 * It uses UDP as protocol, and offers public send- and receive-methods.
 *
 */
public class RCSSConnection {

	/**
	 * DatagramSocket, which listens on a defined port for incoming UDP-Packets.
	 */
	private DatagramSocket socket = null;

	/**
	 * DatagramPacket in which data is wrapped into and sent to the server. 
	 */
	private DatagramPacket sendPacket = null;

	/**
	 * DatagramPacket, in which incoming data is wrote into.
	 */
	private DatagramPacket recvPacket = null;

	/**
	 * The InetAddress of the server.
	 */
	private InetAddress host = null;

	/**
	 * The port of the server.
	 */
	private int port = 6000;

	/**
	 * The host-name of the server.
	 */
	private String hostname = "localhost";

	/**
	 * The buffer, in which raw data from a received message is wrote into.
	 * This can be returned as string.
	 */
	private ByteBuffer receiveBuffer = null;

	/**
	 * The buffer, in which a string for a sending message is wrote into.
	 * This can be returned as raw data for sending.
	 */
	private ByteBuffer sendBuffer = null;

	/**
	 * Flag, indicating, if a port was given.
	 */
	private boolean no_port = true;

	/**
	 * The timeout for receiving messages (in milliseconds). Note that this 
	 * will cause the agent to terminate, if for this duration no message is 
	 * received, assuming that the server is dead.
	 */
	private int timeout = 3000;

	/**
	 * The latest command, that should be sent to the server.
	 */
	private String command = null;

	/**
	 * <code>RCSSConnection</code> constructor This constructor initializes all
	 * necessary member variables for the connection to the soccer server.
	 * 
	 * @param port -
	 *            the server port
	 * @param hostname -
	 *            the server host
	 */
	public RCSSConnection(String hostname, int port) {
		this.hostname = hostname;
		this.port = port;
		try {
			this.host = InetAddress.getByName(this.hostname);
			this.receiveBuffer = new ByteBuffer(4000);
			this.recvPacket = new DatagramPacket(this.receiveBuffer
					.getByteArray(), this.receiveBuffer.length());
			this.sendBuffer = new ByteBuffer(4000);
			this.sendPacket = new DatagramPacket(
					this.sendBuffer.getByteArray(), this.sendBuffer.length(),
					this.host, port);
			this.socket = new DatagramSocket();
			this.socket.setSoTimeout(this.timeout);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * Method for sending data to the rcssserver
	 * 
	 * @param message -
	 *            the message
	 * @throws IOException -
	 *             occurs on unexpected io-errors
	 */
	public void send(String message) throws IOException {
		this.sendBuffer.reset();
		this.sendBuffer.setString(message);
		this.sendPacket.setData(this.sendBuffer.getByteArray());
		this.sendPacket.setLength(this.sendBuffer.length());
		this.sendPacket.setAddress(this.host);
		this.sendPacket.setPort(this.port);
		this.socket.send(this.sendPacket);
		// debug only
		this.command = message;
	}

	/**
	 * This method receives DataGramms form from the rcssserver, and returns
	 * the contained data as string. Note that this method blocks the calling
	 * thread and will return <code>null</code>, if a timeout occurs. This will
	 * shutdown the agent.
	 * 
	 * @return - the received string
	 */
	public String receive() {
		try {
			this.receiveBuffer.reset();
			this.recvPacket.setData(this.receiveBuffer.getByteArray());
			this.recvPacket.setLength(this.receiveBuffer.getByteArray().length);
			this.socket.receive(this.recvPacket);

			// once check host and port
			if (this.no_port) {
				this.host = this.recvPacket.getAddress();
				this.port = this.recvPacket.getPort();
				this.no_port = false;
			}
			String str = this.receiveBuffer.getString();
			return str;
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * This method return the last sent command
	 * 
	 * @return a string containing the last command!
	 */
	public String getCommand() {
		return this.command;
	}

}
